/**
 * 
 */
package voisinages;

import java.util.ArrayList;

import programme.Portefeuille;
import programme.PortefeuilleDeterministe;
import programme.Programme;
import programme.Solution;
import programme.Variable;

/**
 * @author port
 *
 */
public class ComplementAlpha extends Voisinage {

	Portefeuille prog;
	PortefeuilleDeterministe pd;
	
	public ComplementAlpha(Portefeuille p){
		prog = p;
		pd = (PortefeuilleDeterministe)p;
	}
	
	
	
	public Solution mouvement(Solution s, int distance) {

		Solution solution = new Solution(s);
		
		ArrayList<Variable> titres = prog.getTitres();
		ArrayList<Variable> choix = prog.getChoix();

		ArrayList<Variable> titresModif = new ArrayList<Variable>();
		ArrayList<Variable> choixModif = new ArrayList<Variable>();

		Variable var;

		int indice;

		//System.out.println("\tDebut mouvement");
		
		do{

			// Choix des variables à inverser. La première doit etre non nulle
			
			boolean firstDone = false;
			
			for (int i = 0; i < distance; i++){

				do{
					indice = (int)(Math.random() * titres.size());
					var = titres.get(indice);
					
					if (solution.getValeurs().get(var) > pd.getEpsilon())
						firstDone = true;
				}while(titresModif.contains(var) && firstDone);

				titresModif.add(var);
				choixModif.add(choix.get(indice));

			}

			//System.out.println("\tMouvement");
			solution = inverse(solution, distance, titresModif, choixModif);
			
			titresModif.clear();
			choixModif.clear();

		}while(!((Programme)prog).satisfaitContraintes(solution));
		
		//System.out.println("\tFin mouvement");
		
		return solution;

	}

	
	
	public Solution optimumLocal(Solution solution, int distance){

		Solution s = new Solution(solution);
		
		ArrayList<Variable> titres = prog.getTitres();
		ArrayList<Variable> choix = prog.getChoix();
		
		ArrayList<Variable> variables = new ArrayList<Variable>(titres);
		variables.addAll(choix);
		
		ArrayList<Variable> titresModif = new ArrayList<Variable>();
		ArrayList<Variable> choixModif = new ArrayList<Variable>();
		
		Solution optimum = new Solution(variables);
		Solution test;

		//System.out.println("\tDebut optimumLocal");
		
		// On essaie toutes les possibilités d'inversions contigues 
		// TODO (à améliorer)
		for (int i = 0; i < titres.size() - distance + 1; i++){

			for (int j = 0; j < distance; j++){
				titresModif.add(titres.get(j));
				choixModif.add(choix.get(j));
			}
			
			test = inverse(s, distance, titresModif, choixModif);
			
			if(prog.getObjectif().eval(test) < prog.getObjectif().eval(optimum)){
				optimum = test;
			}
			
			titresModif.clear();
			choixModif.clear();
			
		}
		
		//System.out.println("\tFin OptimumLocal");
		
		return optimum;

	}

	/**
	 * Inverse, dans la Solution s, les valeurs des titres de titresModif en mettant éventuellement à
	 * jour les choixModif (Yi), et pour d variables
	 * 
	 * @param s				La solution modifiée
	 * @param d				Le nombre de variables à modifier
	 * @param titresModif	Les titres à modifier
	 * @param choixModif	Les Yi(choix) correspondants
	 * @return
	 */
	private Solution inverse(Solution solution, int d, ArrayList<Variable> titresModif, ArrayList<Variable> choixModif){
		
		Solution s = new Solution(solution);
		
		double value;
		
		int i2;
		
		for (int i = 0; i < d; i++){
			
			i2 = (i+1)%d;
			
			if (i != d-1){
				
				// on met à jour les choix (Yi)
				
				if (s.getValeurs().get(titresModif.get(i)) > 0){
					s.getValeurs().put(choixModif.get(i), 0.0);
					s.getValeurs().put(choixModif.get(i2), 1.0);
				}
				
				if (s.getValeurs().get(titresModif.get(i2)) > 0){
					s.getValeurs().put(choixModif.get(i2), 0.0);
					s.getValeurs().put(choixModif.get(i), 1.0);
				}
				
				// on inverse les titres (Xi)
				
				value = s.getValeurs().get(titresModif.get(i2));
				
				s.getValeurs().put( titresModif.get(i2), new Double(s.getValeurs().get(titresModif.get(i))) );
				s.getValeurs().put( titresModif.get(i), value );
			}
			
		}
		return s;

	}
	
}
